package com.haiqiu.common.utils.web;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT 工具类
 *
 * @author HaiQiu
 */
@Component
@Slf4j
public class JwtTokenUtil implements Serializable {

    /**
     * 签发机构
     */
    @Value("${jwt.claim.username}")
    private String claimUsername;

    /**
     * 过期时间(毫秒)
     */
    @Value("${jwt.expiration.time}")
    private long expirationTime;
    /**
     * JWT密码
     */
    @Value("${jwt.secret}")
    private String secret;


    @Value("${jwt.authorization}")
    private String authorization;

    @Value("${jwt.header}")
    private String header;


    /**
     * 签发JWT
     */
    public String generateToken(Long userId,String username) {
        Map<String, Object> claims = new HashMap<>(16);
        claims.put("userId", userId);
        claims.put(claimUsername, username);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(Instant.now().toEpochMilli() + expirationTime))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }


    /**
     * 获取token是否过期
     */
    public Boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 根据token获取username
     */
    public String getUsername(String token) {
        String username = (String) getClaimsFromToken(token).get(claimUsername);
        return username;
    }

    /**
     * 根据token获取username
     */
    public Long getUserId(String token) {
        long userId = (Long) getClaimsFromToken(token).get("userId");
        return userId;
    }

    /**
     * 根据request获取token获取username
     */
    public String getUsername(HttpServletRequest request) {
        //获取请求头token
        String authToken = request.getHeader(this.authorization);
        //token不为空
        if (!StringUtils.isEmpty(authToken)) {
            //截取 bearer 后面的字符串  并且 两端去空格（获取token）
            String token = authToken.substring(this.header.length()).trim();
            String username = getClaimsFromToken(token) == null ?
                    null : (String) getClaimsFromToken(token).get(claimUsername);
            return username;
        }
        return null;
}


    /**
     * 根据request获取token获取userId
     */
    public Long getUserId(HttpServletRequest request) {
        //获取请求头token
        String authToken = request.getHeader(this.authorization);
        //token不为空
        if (!StringUtils.isEmpty(authToken)) {
            //截取 bearer 后面的字符串  并且 两端去空格（获取token）
            String token = authToken.substring(this.header.length()).trim();
            Integer id = (Integer) getClaimsFromToken(token).get("userId");
            long userId = id;
            return userId;
        }
        return null;
    }


    /**
     * 根据request获取token
     */
    public String getToken(HttpServletRequest request) {
        //获取请求头token
        String authToken = request.getHeader(this.authorization);
        //token不为空
        if (!StringUtils.isEmpty(authToken)) {
            //截取 bearer 后面的字符串  并且 两端去空格（获取token）
            return authToken.substring(this.header.length()).trim();
        }
        return null;
    }

    /**
     * 获取token的过期时间
     */
    public Date getExpirationDateFromToken(String token) {
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration;
    }

    /**
     * 解析JWT
     */
    private Claims getClaimsFromToken(String token) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            return claims;
        }catch (Exception e){
            log.info("Token解析异常");
            return null;
        }
    }
}